package com.xdl.modules.system.controller;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.beluga.notice.sms.SMSClient;
import com.beluga.notice.sms.SMSEntity;
import com.xdl.common.constants.CommonConstants;
import com.xdl.common.constants.ResponseStatus;
import com.xdl.common.exception.BelugaException;
import com.xdl.common.jwt.JWTHelper;
import com.xdl.common.jwt.JWTInfo;
import com.xdl.common.response.ResponseResult;
import com.xdl.common.utils.MD5Utils;
import com.xdl.common.utils.PasswordUtil;
import com.xdl.common.utils.StringUtils;
import com.xdl.configuration.BaseContextHandler;
import com.xdl.modules.system.entity.SysDepart;
import com.xdl.modules.system.entity.SysTenant;
import com.xdl.modules.system.entity.SysUser;
import com.xdl.modules.system.model.PhoneLoginModel;
import com.xdl.modules.system.model.RandomImage;
import com.xdl.modules.system.model.SysLoginModel;
import com.wf.captcha.SpecCaptcha;
import com.xdl.modules.system.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@RestController
@RequestMapping("/sys")
@Slf4j
@RequiredArgsConstructor
public class LoginController {

    @Autowired
    private CacheService cacheService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysDepartService departService;

    @Autowired
    private SysTenantService tenantService;

    @Autowired
    private SysDictService sysDictService;

    @Autowired
    private SysLogService logService;

    @Autowired
    private SMSClient smsClient;

    @PostMapping(value = "/login")
    public ResponseResult<JSONObject> login(@RequestBody SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        if (captcha == null) {
            BelugaException.fatal(com.xdl.common.constants.ResponseStatus.CODE_IS_INVALID);
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Utils.MD5Encode(lowerCaseCaptcha + sysLoginModel.getCheckKey(), "utf-8");
        Object checkCode = cacheService.getRandomImage(realKey);
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            log.warn("验证码错误，key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
            return ResponseResult.Error("验证码错误！");
        }
        //1. 校验用户是否有效
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, sysLoginModel.getUsername());
        SysUser sysUser = sysUserService.getOne(queryWrapper);
        if (sysUser != null && checkUserIsEffective(sysUser)) {
            String userpassword = PasswordUtil.encrypt(sysLoginModel.getUsername(), sysLoginModel.getPassword(), sysUser.getSalt());
            String syspassword = sysUser.getPassword();
            if (!syspassword.equals(userpassword)) {
                return ResponseResult.Error(com.xdl.common.constants.ResponseStatus.PASSWORD_IS_ERROR.getValue());
            }
            /**删除验证码*/
            cacheService.delKey(realKey);
            JSONObject result = this.getUserInfo(sysUser);
            return ResponseResult.Success(result);
        }
        return ResponseResult.Success();
    }

    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/logout")
    public ResponseResult<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstants.X_ACCESS_TOKEN);
        if (StringUtils.isEmpty(token)) {
            return ResponseResult.Error("退出登录失败！");
        }
        String userid = BaseContextHandler.getUserID();
        Assert.notNull(userid, "账号登陆异常！");
        SysUser sysUser = sysUserService.getById(userid);
        if (sysUser != null) {
            log.info(" 用户名:  " + sysUser.getRealname() + ",退出成功！ ");
            //清空用户登录Token缓存
            cacheService.delKey(CommonConstants.PREFIX_USER_TOKEN + token);
            //redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
            return ResponseResult.Success("退出登录成功！");
        } else {
            return ResponseResult.Error("Token无效!");
        }
    }


    private JSONObject getUserInfo(SysUser sysUser) {
        // 获取用户部门信息
        JSONObject obj = new JSONObject();
        List<SysDepart> departs = departService.queryUserDeparts(sysUser.getId());
        obj.put("departs", departs);
        if (departs == null || departs.size() == 0) {
            obj.put("multi_depart", 0);
        } else if (departs.size() == 1) {
            sysUserService.updateUserDepart(sysUser.getUsername(), departs.get(0).getOrgCode());
            obj.put("multi_depart", 1);
        } else {
            //查询当前是否有登录部门
            SysUser sysUserById = sysUserService.getById(sysUser.getId());
            if (StringUtils.isEmpty(sysUserById.getOrgCode())) {
                sysUserService.updateUserDepart(sysUser.getUsername(), departs.get(0).getOrgCode());
            }
            obj.put("multi_depart", 2);
        }
        String tenantIds = sysUser.getRelTenantIds();
        if (StringUtils.isNotEmpty(tenantIds)) {
            List<Integer> tenantIdList = new ArrayList<>();
            for (String id : tenantIds.split(",")) {
                tenantIdList.add(Integer.valueOf(id));
            }
            // 该方法仅查询有效的租户，如果返回0个就说明所有的租户均无效。
            List<SysTenant> tenantList = tenantService.queryEffectiveTenant(tenantIdList);
            if (tenantList.size() == 0) {
                BelugaException.fatal("与该用户关联的租户均已被冻结，无法登录！");
            } else {
                obj.put("tenantList", tenantList);
            }
        }
        // 生成token JwtUtil.sign(username, syspassword)
        String token = JWTHelper.generateToken(JWTInfo.builder().userName(sysUser.getUsername()).userId(sysUser.getId()).build(), 1);
        // 设置token缓存有效时间
        cacheService.setCache(CommonConstants.PREFIX_USER_TOKEN + token, token, JWTHelper.EXPIRE_TIME * 2 / 1000);
        obj.put("token", token);
        obj.put("userInfo", sysUser);
        obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
        return obj;
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("loginfo")
    public ResponseResult<JSONObject> loginfo() {
        JSONObject obj = new JSONObject();
        //update-begin--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        // 获取一天的开始和结束时间
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date dayStart = calendar.getTime();
        calendar.add(Calendar.DATE, 1);
        Date dayEnd = calendar.getTime();
        // 获取系统访问记录
        Long totalVisitCount = logService.findTotalVisitCount();
        obj.put("totalVisitCount", totalVisitCount);
        Long todayVisitCount = logService.findTodayVisitCount(dayStart, dayEnd);
        obj.put("todayVisitCount", todayVisitCount);
        Long todayIp = logService.findTodayIp(dayStart, dayEnd);
        obj.put("todayIp", todayIp);
        return ResponseResult.Success(obj);
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("visitInfo")
    public ResponseResult<List<Map<String, Object>>> visitInfo() {
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date dayEnd = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        Date dayStart = calendar.getTime();
        List<Map<String, Object>> list = logService.findVisitCount(dayStart, dayEnd);
        return ResponseResult.Success(list);
    }


    private boolean checkUserIsEffective(SysUser sysUser) {
        if (CommonConstants.DEL_FLAG_1.equals(sysUser.getDelFlag())) {
            BelugaException.fatal(com.xdl.common.constants.ResponseStatus.ACCOUNT_DISABLED);
        }
        //情况3：根据用户信息查询，该用户已冻结
        if (CommonConstants.USER_FREEZE.equals(sysUser.getStatus())) {
            BelugaException.fatal(ResponseStatus.ACCOUNT_LOCKED);
        }
        return true;
    }


    /**
     * 生成验证码
     *
     * @param key
     * @return
     */
    @GetMapping(value = "/randomImage/{key}")
    public ResponseResult<?> randomImage(@PathVariable String key) {
        // png类型
        SpecCaptcha captcha = new SpecCaptcha(105, 35);
        String text = captcha.text();// 获取验证码的字符
        char[] chars = captcha.textChar();// 获取验证码的字符数组
        //存到redis中
        String lowerCaseCode = text.toLowerCase();
        String realKey = MD5Utils.MD5Encode(lowerCaseCode + key, "utf-8");
        // 验证码信息
        RandomImage image = new RandomImage();
        image.setBase64(captcha.toBase64());
        boolean cache = cacheService.cacheRandomImage(realKey, lowerCaseCode, 60);
        return ResponseResult.Success(image);
    }

    @GetMapping("/getVerifyCode/{phone}")
    public ResponseResult getVerifyCode(@PathVariable("phone") String phone) throws Exception {
        Object code = cacheService.getCache(phone);
        Assert.isNull(code, phone + ":" + code + "未过期");
        //生产验证码并存储
        code = RandomUtil.randomNumbers(4);
        HashMap<String, Object> param = new HashMap<>();
        param.put("code", code);
        SMSEntity params=new SMSEntity();
        params.setPhone(phone);
        params.setSignName("新动力");
        params.setTemplateCode("SMS_241915392");
        params.setSmsParams(param);
        boolean isSend = smsClient.sendSMS(params);
        if (isSend) {
            cacheService.setCache(phone, code.toString(), 60 * 5);
            return ResponseResult.Success();
        } else {
            return ResponseResult.Error();
        }
    }


    @PostMapping("/phoneLogin")
    public ResponseResult<JSONObject> phoneLogin(@RequestBody PhoneLoginModel model) {
        String phone = model.getMobile();
        //校验用户有效性
        QueryWrapper<SysUser> userwrapper = new QueryWrapper<>();
        userwrapper.lambda().eq(SysUser::getPhone, phone);
        SysUser sysUser = sysUserService.getOne(userwrapper);
        if (sysUser != null && checkUserIsEffective(sysUser)) {
            String smscode = model.getCaptcha();
            Object code = cacheService.getCache(phone);
            if (!smscode.equals(code)) {
                return ResponseResult.Error("手机验证码错误");
            }
            /**删除验证码*/
            cacheService.delKey(phone);
            JSONObject result = this.getUserInfo(sysUser);
            return ResponseResult.Success(result);
        }
        return ResponseResult.Success();
    }


}
